home *** CD-ROM | disk | FTP | other *** search
- /* MS-DOS specific C utilities.
- Copyright (C) 1993, 1994 Free Software Foundation, Inc.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: FSF 19.28. */
-
- /* Contributed by Morten Welinder */
-
- /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
-
- #define DONT_ENCAPSULATE
-
- #include <config.h>
-
- #ifdef MSDOS
- #include <sys/param.h>
- #include <sys/time.h>
- #include <dos.h>
- #include "lisp.h"
- #include "dosfns.h"
- #include "msdos.h"
- #include "systime.h"
- #include "termhooks.h"
- #include "frame.h"
- #include <go32.h>
- #include <pc.h>
- /* #include <process.h> */
- /* Damn that local process.h! Instead we can define P_WAIT ourselves. */
- #define P_WAIT 1
-
- static int break_stat; /* BREAK check mode status. */
- static int stdin_stat; /* stdin IOCTL status. */
- static int extended_kbd; /* 101 (102) keyboard present. */
-
- int have_mouse; /* Mouse present? */
- static int mouse_last_x;
- static int mouse_last_y;
-
- /* Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
- by Dos. Determine the keyboard type. */
- int
- dos_ttraw (void)
- {
- union REGS inregs, outregs;
-
- inregs.h.ah = 0xc0;
- int86 (0x15, &inregs, &outregs);
- extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
-
- break_stat = getcbrk ();
- setcbrk (0);
- install_ctrl_break_check ();
- have_mouse = mouse_init1 ();
-
- inregs.x.ax = 0x4400; /* Get IOCTL status. */
- inregs.x.bx = 0x00; /* 0 = stdin. */
- intdos (&inregs, &outregs);
- stdin_stat = outregs.h.dl;
-
- inregs.x.dx = (outregs.x.dx | 0x0020) & 0x0027; /* raw mode */
- inregs.h.al = 0x01;
- intdos (&inregs, &outregs);
- return !outregs.x.cflag;
- }
-
- /* Restore status of standard input and Ctrl-C checking. */
- int
- dos_ttcooked (void)
- {
- union REGS inregs, outregs;
-
- setcbrk (break_stat);
- if (have_mouse) mouse_off ();
-
- inregs.x.ax = 0x4401; /* Set IOCTL status. */
- inregs.x.bx = 0x00; /* 0 = stdin. */
- inregs.x.dx = stdin_stat;
- intdos (&inregs, &outregs);
- return !outregs.x.cflag;
- }
-
- static unsigned short
- ibmpc_translate_map[] =
- {
- /* --------------- 00 to 0f --------------- */
- 0, /* Ctrl Break */
- 0xff1b, /* Escape */
- 0xffb1, /* Keypad 1 */
- 0xffb2, /* Keypad 2 */
- 0xffb3, /* Keypad 3 */
- 0xffb4, /* Keypad 4 */
- 0xffb5, /* Keypad 5 */
- 0xffb6, /* Keypad 6 */
- 0xffb7, /* Keypad 7 */
- 0xffb8, /* Keypad 8 */
- 0xffb9, /* Keypad 9 */
- 0xffb0, /* Keypad 0 */
- '-', '=',
- 0xff08, /* Backspace */
- 0xff74, /* (Shift) Tab [Tab doesn't use this table] */
-
- /* --------------- 10 to 1f --------------- */
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
- 0xff8d, /* Keypad Enter */
- 0, /* Ctrl */
- 'a', 's',
-
- /* --------------- 20 to 2f --------------- */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
- 0, /* Left shift */
- '\\', 'z', 'x', 'c', 'v',
-
- /* --------------- 30 to 3f --------------- */
- 'b', 'n', 'm', ',', '.',
- 0xffaf, /* Grey / */
- 0, /* Right shift */
- 0xffaa, /* Grey * */
- 0, /* Alt */
- ' ',
- 0, /* Caps Lock */
- 0xffbe, /* F1 */
- 0xffbf, /* F2 */
- 0xffc0, /* F3 */
- 0xffc1, /* F4 */
- 0xffc2, /* F5 */
-
- /* --------------- 40 to 4f --------------- */
- 0xffc3, /* F6 */
- 0xffc4, /* F7 */
- 0xffc5, /* F8 */
- 0xffc6, /* F9 */
- 0xffc7, /* F10 */
- 0, /* Num Lock */
- 0, /* Scroll Lock */
- 0xff50, /* Home */
- 0xff52, /* Up */
- 0xff55, /* Page Up */
- 0xffad, /* Grey - */
- 0xff51, /* Left */
- 0xffb5, /* Keypad 5 */
- 0xff53, /* Right */
- 0xffab, /* Grey + */
- 0xff57, /* End */
-
- /* --------------- 50 to 5f --------------- */
- 0xff54, /* Down */
- 0xff56, /* Page Down */
- 0xff63, /* Insert */
- 0xffff, /* Delete */
- 0xffbe, /* (Shift) F1 */
- 0xffbf, /* (Shift) F2 */
- 0xffc0, /* (Shift) F3 */
- 0xffc1, /* (Shift) F4 */
- 0xffc2, /* (Shift) F5 */
- 0xffc3, /* (Shift) F6 */
- 0xffc4, /* (Shift) F7 */
- 0xffc5, /* (Shift) F8 */
- 0xffc6, /* (Shift) F9 */
- 0xffc7, /* (Shift) F10 */
- 0xffbe, /* (Ctrl) F1 */
- 0xffbf, /* (Ctrl) F2 */
-
- /* --------------- 60 to 6f --------------- */
- 0xffc0, /* (Ctrl) F3 */
- 0xffc1, /* (Ctrl) F4 */
- 0xffc2, /* (Ctrl) F5 */
- 0xffc3, /* (Ctrl) F6 */
- 0xffc4, /* (Ctrl) F7 */
- 0xffc5, /* (Ctrl) F8 */
- 0xffc6, /* (Ctrl) F9 */
- 0xffc7, /* (Ctrl) F10 */
- 0xffbe, /* (Alt) F1 */
- 0xffbf, /* (Alt) F2 */
- 0xffc0, /* (Alt) F3 */
- 0xffc1, /* (Alt) F4 */
- 0xffc2, /* (Alt) F5 */
- 0xffc3, /* (Alt) F6 */
- 0xffc4, /* (Alt) F7 */
- 0xffc5, /* (Alt) F8 */
-
- /* --------------- 70 to 7f --------------- */
- 0xffc6, /* (Alt) F9 */
- 0xffc7, /* (Alt) F10 */
- 0xff6d, /* (Ctrl) Sys Rq */
- 0xff51, /* (Ctrl) Left */
- 0xff53, /* (Ctrl) Right */
- 0xff57, /* (Ctrl) End */
- 0xff56, /* (Ctrl) Page Down */
- 0xff50, /* (Ctrl) Home */
- '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
-
- /* --------------- 80 to 8f --------------- */
- '9', '0', '-', '=', /* (Alt) */
- 0xff55, /* (Ctrl) Page Up */
- 0xffc8, /* F11 */
- 0xffc9, /* F12 */
- 0xffc8, /* (Shift) F11 */
- 0xffc9, /* (Shift) F12 */
- 0xffc8, /* (Ctrl) F11 */
- 0xffc9, /* (Ctrl) F12 */
- 0xffc8, /* (Alt) F11 */
- 0xffc9, /* (Alt) F12 */
- 0xff52, /* (Ctrl) Up */
- 0xffae, /* (Ctrl) Grey - */
- 0xffb5, /* (Ctrl) Keypad 5 */
-
- /* --------------- 90 to 9f --------------- */
- 0xffab, /* (Ctrl) Grey + */
- 0xff54, /* (Ctrl) Down */
- 0xff63, /* (Ctrl) Insert */
- 0xffff, /* (Ctrl) Delete */
- 0xff09, /* (Ctrl) Tab */
- 0xffaf, /* (Ctrl) Grey / */
- 0xffaa, /* (Ctrl) Grey * */
- 0xff50, /* (Alt) Home */
- 0xff52, /* (Alt) Up */
- 0xff55, /* (Alt) Page Up */
- 0, /* NO KEY */
- 0xff51, /* (Alt) Left */
- 0, /* NO KEY */
- 0xff53, /* (Alt) Right */
- 0, /* NO KEY */
- 0xff57, /* (Alt) End */
-
- /* --------------- a0 to af --------------- */
- 0xff54, /* (Alt) Down */
- 0xff56, /* (Alt) Page Down */
- 0xff63, /* (Alt) Insert */
- 0xffff, /* (Alt) Delete */
- 0xffaf, /* (Alt) Grey / */
- 0xff09, /* (Alt) Tab */
- 0xff0d /* (Alt) Enter */
- };
-
- /* Get a char from keyboard. Function keys are put into the event queue. */
- static int
- dos_rawgetc (void)
- {
- struct input_event event;
- struct timeval tv;
- union REGS regs;
- int ctrl_p, alt_p, shift_p;
-
- /* Calculate modifier bits */
- regs.h.ah = extended_kbd ? 0x12 : 0x02;
- int86 (0x16, ®s, ®s);
- ctrl_p = ((regs.h.al & 4) != 0);
- shift_p = ((regs.h.al & 3) != 0);
- /* Please be very careful here not to break international keyboard support.
- When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
- characters like { and } if their positions are overlaid. */
- alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
-
- /* The following condition is equivalent to `kbhit ()', except that
- it uses the bios to do its job. This pleases DESQview/X. */
- while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
- int86 (0x16, ®s, ®s),
- (regs.x.flags & 0x40) == 0)
- {
- union REGS regs;
- unsigned char c;
- int sc, code;
-
- regs.h.ah = extended_kbd ? 0x10 : 0x00;
- int86 (0x16, ®s, ®s);
- c = regs.h.al;
- sc = regs.h.ah;
-
- /* Determine from the scan code if a keypad key was pressed. */
- if (c >= '0' && c <= '9' && sc > 0xb)
- sc = (c == '0') ? 0xb : (c - '0' + 1), c = 0;
- else if (sc == 0x53 && c != 0xe0)
- {
- code = 0xffae; /* Keypad decimal point/comma. */
- goto nonascii;
- }
- else if (sc == 0xe0)
- {
- switch (c)
- {
- case 10: /* Ctrl Enter */
- case 13:
- sc = 0x1c;
- break;
- case '/':
- sc = 0x35;
- break;
- default:
- sc = 0;
- };
- c = 0;
- }
-
- if (c == 0
- || c == ' '
- || alt_p
- || (ctrl_p && shift_p)
- || (c == 0xe0 && sc != 0) /* Pseudo-key */
- || sc == 0x37 /* Grey * */
- || sc == 0x4a /* Grey - */
- || sc == 0x4e /* Grey + */
- || sc == 0x0e) /* Back space *key*, not Ctrl-h */
- {
- if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
- code = 0;
- else
- code = ibmpc_translate_map[sc];
- if (code != 0)
- {
- if (code >= 0x100)
- {
- nonascii:
- event.kind = non_ascii_keystroke;
- event.code = (code & 0xff) + 0xff00;
- }
- else
- {
- /* Don't return S- if we don't have to. `shifted' is
- supposed to be the shifted versions of the characters
- in `unshifted'. Unfortunately, this is only true for
- US keyboard layout. If anyone knows how to do this
- right, please tell us. */
- static char *unshifted
- = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
- static char *shifted
- = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
- char *pos;
-
- if (shift_p && (pos = strchr (unshifted, code)))
- {
- c = shifted[pos - unshifted];
- shift_p = 0;
- }
- else
- if (c == 0) c = code;
- event.kind = ascii_keystroke;
- event.code = c;
- }
- event.modifiers
- = (shift_p ? shift_modifier : 0)
- + (ctrl_p ? ctrl_modifier : 0)
- + (alt_p ? meta_modifier : 0);
- /* EMACS == Enter Meta Alt Control Shift */
- event.frame_or_window = selected_frame;
- gettimeofday (&tv, NULL);
- event.timestamp = tv.tv_usec;
- kbd_buffer_store_event (&event);
- }
- } else
- return c;
- }
-
- if (have_mouse)
- {
- int but, press, x, y, ok;
-
- /* Check for mouse movement *before* buttons. */
- mouse_check_moved ();
-
- for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
- for (press = 0; press < 2; press++)
- {
- if (press)
- ok = mouse_pressed (but, &x, &y);
- else
- ok = mouse_released (but, &x, &y);
- if (ok)
- {
- event.kind = mouse_click;
- event.code = but;
- event.modifiers
- = (shift_p ? shift_modifier : 0)
- + (ctrl_p ? ctrl_modifier : 0)
- + (alt_p ? meta_modifier : 0)
- + (press ? down_modifier : up_modifier);
- event.x = x;
- event.y = y;
- event.frame_or_window = selected_frame;
- gettimeofday (&tv, NULL);
- event.timestamp = tv.tv_usec;
- kbd_buffer_store_event (&event);
- }
- }
- }
-
- return -1;
- }
-
- static int prev_get_char = -1;
-
- /* Return 1 if a key is ready to be read without suspending execution. */
- int
- dos_keysns (void)
- {
- if (prev_get_char != -1)
- return 1;
- else
- return ((prev_get_char = dos_rawgetc ()) != -1);
- }
-
- /* Read a key. Return -1 if no key is ready. */
- int
- dos_keyread (void)
- {
- if (prev_get_char != -1)
- {
- int c = prev_get_char;
- prev_get_char = -1;
- return c;
- }
- else
- return dos_rawgetc (void);
- }
-
- /* Hostnames for a pc are not really funny, but they are used in change log
- so we emulate the best we can. */
- int
- gethostname (char *p, int size)
- {
- char *q = egetenv ("HOSTNAME");
-
- if (!q) q = "pc";
- strcpy (p, q);
- return 0;
- }
-
- /* Destructively turn backslashes into slashes. */
- void
- dostounix_filename (char *p)
- {
- while (*p)
- {
- if (*p == '\\')
- *p = '/';
- p++;
- }
- }
-
- /* Destructively turn slashes into backslashes. */
- void
- unixtodos_filename (char *p)
- {
- while (*p)
- {
- if (*p == '/')
- *p = '\\';
- p++;
- }
- }
-
- /* Get the default directory for a given drive. 0=def, 1=A, 2=B, ... */
- int
- getdefdir (int drive, char *dst)
- {
- union REGS regs;
-
- *dst++ = '/';
- regs.h.dl = drive;
- regs.x.si = (int) dst;
- regs.h.ah = 0x47;
- intdos (®s, ®s);
- return !regs.x.cflag;
- }
-
- /* Remove all CR's that are followed by a LF. */
- int
- crlf_to_lf (int n, unsigned char *buf)
- {
- unsigned char *np = buf;
- unsigned char *startp = buf;
- unsigned char *endp = buf + n;
- unsigned char c;
-
- if (n == 0)
- return n;
- while (buf < endp - 1)
- {
- if (*buf == 0x0d)
- {
- if (*(++buf) != 0x0a)
- *np++ = 0x0d;
- }
- else
- *np++ = *buf++;
- }
- if (buf < endp)
- *np++ = *buf++;
- return np - startp;
- }
-
-
- /* Run command as specified by ARGV in directory DIR.
- The command is run with input from TEMPIN and output to file TEMPOUT. */
- int
- run_msdos_command (unsigned char **argv, Lisp_Object dir, int tempin,
- int tempout)
- {
- char *saveargv1, *saveargv2, **envv;
- char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
- int msshell, result = -1;
- int in, out, inbak, outbak, errbak;
- Lisp_Object cmd;
-
- /* Get current directory as MSDOS cwd is not per-process. */
- getwd (oldwd);
-
- cmd = Ffile_name_nondirectory (build_string (argv[0]));
- msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
- && !strcmp ("-c", argv[1]);
- if (msshell)
- {
- saveargv1 = argv[1];
- saveargv2 = argv[2];
- argv[1] = "/c";
- if (argv[2])
- {
- char *p = alloca (strlen (argv[2]) + 1);
-
- strcpy (argv[2] = p, saveargv2);
- while (*p && isspace ((unsigned char) *p))
- p++;
- while (*p && !isspace ((unsigned char) *p))
- if (*p == '/')
- *p++ = '\\';
- else
- p++;
- }
- }
-
- /* Build the environment array. */
- {
- extern Lisp_Object Vprocess_environment;
- Lisp_Object tmp, lst;
- int i, len;
-
- lst = Vprocess_environment;
- len = XINT (Flength (lst));
-
- envv = alloca ((len + 1) * sizeof (char *));
- for (i = 0; i < len; i++)
- {
- tmp = Fcar (lst);
- lst = Fcdr (lst);
- CHECK_STRING (tmp, 0);
- envv[i] = alloca (string_length (XSTRING (tmp)) + 1);
- strcpy (envv[i], string_data (XSTRING (tmp)));
- }
- envv[len] = (char *) 0;
- }
-
- if (XTYPE (dir) == Lisp_String)
- chdir (string_data (XSTRING (dir)));
- inbak = dup (0);
- outbak = dup (1);
- errbak = dup (2);
- if (inbak < 0 || outbak < 0 || errbak < 0)
- goto done; /* Allocation might fail due to lack of descriptors. */
- dup2 (tempin, 0);
- dup2 (tempout, 1);
- dup2 (tempout, 2);
- dos_ttcooked ();
- result = spawnve (P_WAIT, argv[0], argv, envv);
- dos_ttraw ();
- dup2 (inbak, 0);
- dup2 (outbak, 1);
- dup2 (errbak, 2);
-
- done:
- chdir (oldwd);
- if (msshell)
- {
- argv[1] = saveargv1;
- argv[2] = saveargv2;
- }
- return result;
- }
-
-
- void
- croak (char *badfunc)
- {
- stderr_out ("%s not yet implemented\r\n", badfunc);
- reset_all_devices ();
- exit (1);
- }
-
- /* A list of unimplemented functions that we silently ignore. */
- unsigned alarm (unsigned s) {}
- int fork (void) { return 0; }
- int kill (int x, int y) { return -1; }
- void nice (int p) {}
- void volatile pause (void) {}
- void request_sigio (void) {}
- void unrequest_sigio (void) {}
-
- int
- dos_chdir (CONST char* path)
- {
- int len = strlen (path);
- char *tmp = (char *) alloca (len + 1);
-
- if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
- setdisk (tolower (path[0]) - 'a');
-
- strcpy (tmp, path);
- if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
- tmp[len - 1] = 0;
- return chdir (tmp);
- }
-
- /* Sleep SECS. If KBDOK also return immediately if a key is pressed. */
- void
- sleep_or_kbd_hit (int secs, int kbdok)
- {
- long clnow, clthen;
- struct timeval t;
-
- gettimeofday (&t, NULL);
- clnow = t.tv_sec * 100 + t.tv_usec / 10000;
- clthen = clnow + (100 * secs);
-
- do
- {
- gettimeofday (&t, NULL);
- clnow = t.tv_sec * 100 + t.tv_usec / 10000;
- if (kbdok && detect_input_pending ())
- return;
- }
- while (clnow < clthen);
- }
-
- /* The Emacs root directory as determined by init_environment. */
- static char emacsroot[MAXPATHLEN];
-
- char *
- rootrelativepath (char *rel)
- {
- static char result[MAXPATHLEN + 10];
-
- strcpy (result, emacsroot);
- strcat (result, "/");
- strcat (result, rel);
- return result;
- }
-
- /* Define a lot of environment variables if not already defined. Don't
- remove anything unless you know what you're doing -- lots of code will
- break if one or more of these are missing. */
- void
- init_environment (int argc, char **argv, int skip_args)
- {
- char *s, *t, *root;
- int len;
-
- if (!initialized)
- return;
-
- /* Find our root from argv[0]. Assuming argv[0] is, say,
- "c:/emacs/bin/emacs.exe" our root will be "c:/emacs". */
- len = strlen (argv[0]);
- root = alloca (len + 10); /* A little extra space for the stuff below. */
- strcpy (root, argv[0]);
- while (len > 0 && root[len] != '/' && root[len] != ':')
- len--;
- root[len] = '\0';
- if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
- root[len - 4] = '\0';
- else
- strcpy (root, "c:/emacs"); /* Only under debuggers, I think. */
- len = strlen (root);
- strcpy (emacsroot, root);
-
- /* We default HOME to our root. */
- setenv ("HOME", root, 0);
-
- /* We default EMACSPATH to root + "/bin". */
- strcpy (root + len, "/bin");
- setenv ("EMACSPATH", root, 0);
-
- /* I don't expect anybody to ever use other terminals so the internal
- terminal is the default. */
- setenv ("TERM", "internal", 0);
-
- /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
- downcase it and mirror the backslashes. */
- s = getenv ("COMSPEC");
- if (!s) s = "c:/command.com";
- t = alloca (strlen (s) + 1);
- strcpy (t, s);
- strlwr (t);
- dostounix_filename (t);
- setenv ("SHELL", t, 0);
-
- /* PATH is also downcased and backslashes mirrored. */
- s = getenv ("PATH");
- if (!s) s = "";
- t = alloca (strlen (s) + 3);
- /* Current directory is always considered part of MsDos's path but it is
- not normally mentioned. Now it is. */
- strcat (strcpy (t, ".;"), s);
- strlwr (t);
- dostounix_filename (t); /* Not a single file name, but this should work. */
- setenv ("PATH", t, 1);
-
- /* In some sense all dos users have root privileges, so... */
- setenv ("USER", "root", 0);
- setenv ("NAME", getenv ("USER"), 0);
-
- /* Time zone determined from country code. To make this possible, the
- country code may not span more than one time zone. In other words,
- in the USA, you lose. */
- switch (dos_country_code)
- {
- case 31: /* Belgium */
- case 32: /* The Netherlands */
- case 33: /* France */
- case 34: /* Spain */
- case 36: /* Hungary */
- case 38: /* Yugoslavia (or what's left of it?) */
- case 39: /* Italy */
- case 41: /* Switzerland */
- case 42: /* Tjekia */
- case 45: /* Denmark */
- case 46: /* Sweden */
- case 47: /* Norway */
- case 48: /* Poland */
- case 49: /* Germany */
- /* Daylight saving from last Sunday in March to last Sunday in
- September, both at 2AM. */
- setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
- break;
- case 44: /* United Kingdom */
- case 351: /* Portugal */
- case 354: /* Iceland */
- setenv ("TZ", "GMT+00", 0);
- break;
- case 81: /* Japan */
- case 82: /* Korea */
- setenv ("TZ", "???-09", 0);
- break;
- case 90: /* Turkey */
- case 358: /* Finland */
- case 972: /* Israel */
- setenv ("TZ", "EET-02", 0);
- break;
- }
- tzset ();
- init_gettimeofday ();
- }
-
- /* Flash the screen as a substitute for BEEPs. */
-
- static void
- do_visible_bell (unsigned char xorattr)
- {
- asm volatile
- (" movb $1,%%dl
- visible_bell_0:
- movl _ScreenPrimary,%%eax
- call dosmemsetup
- movl %%eax,%%ebx
- movl %1,%%ecx
- movb %0,%%al
- incl %%ebx
- visible_bell_1:
- xorb %%al,%%gs:(%%ebx)
- addl $2,%%ebx
- decl %%ecx
- jne visible_bell_1
- decb %%dl
- jne visible_bell_3
- visible_bell_2:
- movzwl %%ax,%%eax
- movzwl %%ax,%%eax
- movzwl %%ax,%%eax
- movzwl %%ax,%%eax
- decw %%cx
- jne visible_bell_2
- jmp visible_bell_0
- visible_bell_3:"
- : /* no output */
- : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
- : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
- }
-
- /* At screen position (X,Y), output C characters from string S with
- attribute A. Do it fast! */
-
- static void
- output_string (int x, int y, int s, unsigned char *c, unsigned char *a)
- {
- char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
- asm volatile
- (" movl %1,%%eax
- call dosmemsetup
- movl %%eax,%%edi
- movb %0,%%ah
- movl %2,%%ecx
- movl %3,%%esi
- output_string1:
- movb (%%esi),%%al
- movw %%ax,%%gs:(%%edi)
- addl $2,%%edi
- incl %%esi
- decl %%ecx
- jne output_string1"
- : /* no output */
- : "m" (a), "g" (t), "g" (c), "g" (s)
- : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
- }
-
- static int internal_terminal = 0;
- #undef fflush
-
- int
- internal_flush (FILE *f)
- {
- static char spaces[] = " ";
- static int x;
- static int y;
- unsigned char *cp, *cp0;
- int count, i, j;
-
- if (internal_terminal && f == stdout)
- {
- if (have_mouse) mouse_off ();
- cp = stdout->_base;
- count = stdout->_ptr - stdout->_base;
- while (count > 0)
- {
- switch (*cp++)
- {
- case 27:
- switch (*cp++)
- {
- case '@':
- y = *cp++;
- x = *cp++;
- count -= 4;
- break;
- case 'A':
- ScreenAttrib = *cp++;
- count -= 3;
- break;
- case 'B':
- do_visible_bell (*cp++);
- count -= 3;
- break;
- case 'C':
- ScreenClear ();
- x = y = 0;
- count -= 2;
- break;
- case 'E':
- i = ScreenCols () - x;
- j = x;
- while (i >= sizeof spaces)
- {
- output_string (j, y, spaces, sizeof spaces,
- ScreenAttrib);
- j += sizeof spaces;
- i -= sizeof spaces;
- }
- if (i > 0)
- output_string (j, y, spaces, i, ScreenAttrib);
- count -= 2;
- break;
- case 'R':
- x++;
- count -= 2;
- break;
- case 'U':
- y--;
- count -= 2;
- break;
- case 'X':
- ScreenAttrib ^= *cp++;
- count -= 3;
- break;
- default:
- count -= 2;
- }
- break;
- case 7:
- write (1, "\007", 1);
- count--;
- break;
- case 8:
- x--;
- count--;
- break;
- case 13:
- x = 0;
- count--;
- break;
- case 10:
- y++;
- count--;
- break;
- default:
- cp0 = cp - 1;
- count--;
- while (count > 0 && *cp >= ' ')
- cp++, count--;
- output_string (x, y, cp0, cp - cp0, ScreenAttrib);
- x += (cp - cp0);
- }
- }
- fpurge (stdout);
- ScreenSetCursor (y, x);
- if (have_mouse) mouse_on ();
- }
- else
- /* This is a call to the original fflush. */
- fflush (f);
- }
-
- /* Do we need the internal terminal? */
- void
- internal_terminal_init (void)
- {
- char *term = getenv ("TERM");
-
- internal_terminal
- = (!noninteractive) && term && !strcmp (term, "internal");
- }
-
- /* When time zones are set from Ms-Dos too may C-libraries are playing
- tricks with time values. We solve this by defining our own version
- of `gettimeofday' bypassing GO32. Our version needs to be initialized
- once and after each call to `tzset' with TZ changed. */
-
- static int daylight, gmtoffset;
-
- int
- gettimeofday (struct timeval *tp, struct timezone *tzp)
- {
- if (tp)
- {
- struct time t;
- struct date d;
- struct tm tmrec;
-
- gettime (&t);
- getdate (&d);
- tmrec.tm_year = d.da_year - 1900;
- tmrec.tm_mon = d.da_mon - 1;
- tmrec.tm_mday = d.da_day;
- tmrec.tm_hour = t.ti_hour;
- tmrec.tm_min = t.ti_min;
- tmrec.tm_sec = t.ti_sec;
- tmrec.tm_gmtoff = gmtoffset;
- tmrec.tm_isdst = daylight;
- tp->tv_sec = mktime (&tmrec);
- tp->tv_usec = t.ti_hund * (1000000 / 100);
- }
- if (tzp)
- {
- tzp->tz_minuteswest = gmtoffset;
- tzp->tz_dsttime = daylight;
- }
- return 0;
- }
-
- void
- init_gettimeofday (void)
- {
- time_t ltm, gtm;
- struct tm *lstm;
-
- daylight = 0;
- gmtoffset = 0;
- ltm = gtm = time (NULL);
- ltm = mktime (lstm = localtime (<m));
- gtm = mktime (gmtime (>m));
- daylight = lstm->tm_isdst;
- gmtoffset = (int)(gtm - ltm) / 60;
- }
-
- /* These must be global. */
- static _go32_dpmi_seginfo ctrl_break_vector;
- static _go32_dpmi_registers ctrl_break_regs;
- static int ctrlbreakinstalled = 0;
-
- /* Interrupt level detection of Ctrl-Break. Don't do anything fancy here! */
- void
- ctrl_break_func (_go32_dpmi_registers *regs)
- {
- Vquit_flag = Qt;
- }
-
- void
- install_ctrl_break_check (void)
- {
- if (!ctrlbreakinstalled)
- {
- /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
- was compiler with Djgpp 1.11 maintenance level 5 or later! */
- ctrlbreakinstalled = 1;
- ctrl_break_vector.pm_offset = (int) ctrl_break_func;
- _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
- &ctrl_break_regs);
- _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
- }
- }
-
-
- /* Mouse routines under development follow. Coordinates are in screen
- positions and zero based. Mouse buttons are numbered from left to
- right and also zero based. */
-
- static int mouse_button_translate[NUM_MOUSE_BUTTONS];
- static int mouse_button_count;
-
- void
- mouse_init (void)
- {
- union REGS regs;
-
- regs.x.ax = 0x0007;
- regs.x.cx = 0;
- regs.x.dx = 8 * (ScreenCols () - 1);
- int86 (0x33, ®s, ®s);
-
- regs.x.ax = 0x0008;
- regs.x.cx = 0;
- regs.x.dx = 8 * (ScreenRows () - 1);
- int86 (0x33, ®s, ®s);
-
- mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
- mouse_on ();
- }
-
- void
- mouse_on (void)
- {
- union REGS regs;
-
- regs.x.ax = 0x0001;
- int86 (0x33, ®s, ®s);
- }
-
- void
- mouse_off (void)
- {
- union REGS regs;
-
- regs.x.ax = 0x0002;
- int86 (0x33, ®s, ®s);
- }
-
- void
- mouse_moveto (int x, int y)
- {
- union REGS regs;
-
- regs.x.ax = 0x0004;
- mouse_last_x = regs.x.cx = x * 8;
- mouse_last_y = regs.x.dx = y * 8;
- int86 (0x33, ®s, ®s);
- }
-
- int
- mouse_pressed (int b, int *xp, int *yp)
- {
- union REGS regs;
-
- if (b >= mouse_button_count)
- return 0;
- regs.x.ax = 0x0005;
- regs.x.bx = mouse_button_translate[b];
- int86 (0x33, ®s, ®s);
- if (regs.x.bx)
- *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
- return (regs.x.bx != 0);
- }
-
- int
- mouse_released (int b, int *xp, int *yp)
- {
- union REGS regs;
-
- if (b >= mouse_button_count)
- return 0;
- regs.x.ax = 0x0006;
- regs.x.bx = mouse_button_translate[b];
- int86 (0x33, ®s, ®s);
- if (regs.x.bx)
- *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
- return (regs.x.bx != 0);
- }
-
- void
- mouse_get_pos (FRAME_PTR *f, Lisp_Object *bar_window, Lisp_Object *part,
- enum scroll_bar_part *x, enum scroll_bar_part *y,
- unsigned long *time)
- {
- union REGS regs;
- struct timeval tv;
-
- regs.x.ax = 0x0003;
- int86 (0x33, ®s, ®s);
- *f = selected_frame;
- *bar_window = Qnil;
- gettimeofday (&tv, NULL);
- *x = make_number (regs.x.cx / 8);
- *y = make_number (regs.x.dx / 8);
- *time = tv.tv_usec;
- mouse_moved = 0;
- }
-
- void
- mouse_check_moved (void)
- {
- union REGS regs;
-
- regs.x.ax = 0x0003;
- int86 (0x33, ®s, ®s);
- if (regs.x.cx != mouse_last_x || regs.x.dx != mouse_last_y)
- {
- mouse_moved = 1;
- mouse_last_x = regs.x.cx;
- mouse_last_y = regs.x.dx;
- }
- }
-
- int
- mouse_init1 (void)
- {
- union REGS regs;
- int present;
-
- if (!internal_terminal)
- return 0;
-
- regs.x.ax = 0x0021;
- int86 (0x33, ®s, ®s);
- present = (regs.x.ax & 0xffff) == 0xffff;
- if (!present)
- {
- /* Reportedly, the above doesn't work for some mouse drivers. There
- is an additional detection method that should work, but might be
- a little slower. Use that as an alternative. */
- regs.x.ax = 0x0000;
- int86 (0x33, ®s, ®s);
- present = (regs.x.ax & 0xffff) == 0xffff;
- }
-
- if (present)
- {
- if (regs.x.bx == 3)
- {
- mouse_button_count = 3;
- mouse_button_translate[0] = 0; /* Left */
- mouse_button_translate[1] = 2; /* Middle */
- mouse_button_translate[2] = 1; /* Right */
- }
- else
- {
- mouse_button_count = 2;
- mouse_button_translate[0] = 0;
- mouse_button_translate[1] = 1;
- }
- mouse_position_hook = &mouse_get_pos;
- mouse_init ();
- }
- return present;
- }
-
- /* See xterm.c for more info. */
- void
- pixel_to_glyph_coords (FRAME_PTR f, int pix_x, int pix_y, int *x, int *y,
- void /* XRectangle */ *bounds, int noclip)
- {
- if (bounds) abort ();
-
- /* Ignore clipping. */
-
- *x = pix_x;
- *y = pix_y;
- }
-
- void
- glyph_to_pixel_coords (FRAME_PTR f, int x, int y, int *pix_x, int *pix_y)
- {
- *pix_x = x;
- *pix_y = y;
- }
-
- #endif /* MSDOS */
-